<template>
  <div v-if="wss && waiting" id="shelter">
    <button v-if="false" @click="() => {
      wss = null
      waiting = false
    }">没打开typora？点我</button>
  </div>
  <div id="ws_wrap" ref="ws_wrap" :class="'wrapper ' + (fixed_wrap == 'ws_wrap' ? 'fixed' : '')">
    <div class="fixed_switch" v-html="icon.sticky" @click="switch_fixed_wrap"></div>
    <div v-if="!wss">
      <div class="option_content">
        端口: <input type="text" :value="wsp" @input="e => {
          wsp = e.target.value
        }" @keyup="e => {
          if (e.key == 'Enter') handshake()
        }">
        <button @click="handshake">连接 websocket</button>
      </div>
    </div>

    <div v-if="wss" class="option_content">
      <button v-if="wss" @click="() => {
        wss({ req: 'close' })
          .then(res => console.log(res)
          )
      }">断开 websocket 链接</button>

      <button @click="() => {
        const data = getThis()
        delete data.data_list
        const arr = split_str(JSON.stringify(data))

        keep_waiting()


        wss({
          req: 'setting',
          type: 'path'
        })
          .then(socket => {
            if (!socket.msg.code) save_settings_split(arr, socket.msg.msg, 1, () => {
              conf_local = true
            })
          })

        // wss({
        //   req: 'setting',
        //   type: 'read'
        // })
        //   .then(socket => {
        //     if (!socket.msg.code) {
        //       console.log(socket.msg.msg);

        //     }
        //   })

      }">保存全局设置</button>
      <button @click="init_conf">解析本地设置</button>
      <button v-if="conf_local" @click="() => {
        wss({
          req: 'setting',
          type: 'path'
        })
          .then(socket => {
            if (!socket.msg.code) {
              wss({
                req: 'file',
                type: 'del',
                path: socket.msg.msg
              })
                .then(socket => {
                  if (!socket.msg.code) {
                    msg('<font color=#519aba>全局配置重置成功，刷新页面以重置</font>')
                    conf_local = false
                  } else {
                    msg('全局配置重置失败')
                  }
                })
            }
          })

      }">重置全局设置</button>
      <button v-if="conf_local" @click="() => {
        wss({
          req: 'setting',
          type: 'path'
        })
          .then(socket => {
            if (!socket.msg.code) {
              const path = socket.msg.msg

              wss({
                req: 'file',
                type: 'go',
                path: socket.msg.msg
              })
            }
          })
      }">打开配置文件路径</button>
    </div>
    <div v-if="wss">
      <div class="option_content">
        <span>导出文件夹：</span>
        <input type="text" :value="export_info.export_path" @input="e => set_ls_dataList(e.target.value)" @keyup="e => {
          if (e.key == 'Enter') read_dir()
        }">
        <button @click="() => {
          wss({ req: 'path', type: 'go', path: export_info.export_path })
        }">跳转</button>
        <button @click="() => {
          wss({ req: 'folder_dialog', type: 'folder' })
            .then(socket => {
              if (!socket.msg.code && socket.msg.msg != '') {
                export_info.export_path = socket.msg.msg
                set_ls_dataList(socket.msg.msg)

                read_dir()
              }
            })
        }">修改</button>
        <button ref="read_exportFiles" @click="read_dir">读取</button>
      </div>
      <div class="option_content">
        <button ref="wss_export" @click="() => {
          keep_waiting()

          let data = ''
          export_info.extend_name = ''

          if (export_info.key_data_only) {
            const temp = []
            wordList.forEach(e => {
              if (e.text) {
                temp[e.index] = {
                  // 原文
                  text: e.text,
                  // 释义
                  mean: e.mean,
                  // 翻译
                  trans: e.trans,
                  // 星标
                  star: e.star,
                  // 笔记
                  md: e.md,
                  // 状态
                  stat: {
                    correct: {}
                  },
                  index: e.index
                }
              } else {
                temp[e.index] = {
                  md: e.md,
                  index: e.index
                }
              }
            })

            export_info.extend_name = '_keyDataOnly'

            data = JSON.stringify(temp)
          } else {
            data = JSON.stringify(order_arr())
          }
          const filename = export_info.filename + export_info.extend_name + (export_info.addTime ? get_time() : '') + '.json'
          const efn = export_info.export_path + '/' + filename

          save_settings_split(split_str(data, 4096), efn, 1, read_dir)
          // wss({ req: 'save', data: data, path: efn })
          //   .then(socket => {
          //     // this.$refs.read_exportFiles.click()
          //     // console.log(JSON.parse(data))

          //     if (!socket.msg.code) {
          //       msg({
          //         text: `导出成功 \`${filename}\``
          //       })
          //     } else msg({
          //       text: `导出失败！！！ \`${filename}\``
          //     })

          //     this.$refs.read_exportFiles.click()
          //   })
        }" title="Alt + S">导出</button>

        <div class="checkbox">
          <input type="checkbox" @change="e => {
            export_info.key_data_only = e.target.checked
          }"> <span @click="e => e.target.previousElementSibling.click()">仅导出关键数据</span>
        </div>
        <div class="checkbox">
          <input type="checkbox" :checked="auto_save" @change="e => {
            auto_save = e.target.checked
          }"> <span @click="e => e.target.previousElementSibling.click()">自动保存</span>
          <span v-if="auto_save">
            每 <input type="number" :value="auto_save_dur" min="0.1" style="width: 4em;text-align: right;"> 分钟
          </span>
        </div>

        <div class="checkbox">
          <input type="checkbox" :checked="auto_key_save" @change="e => {
            auto_key_save = e.target.checked
          }"> <span @click="e => e.target.previousElementSibling.click()">关键节点保存</span>
        </div>
        <!-- <div class="checkbox">
          <input type="checkbox" :checked="auto_save_safest" @change="e => {
            auto_save_safest = e.target.checked
          }"> <span @click="e => e.target.previousElementSibling.click()">响应式保存</span>
        </div> -->
      </div>
      <div class="option_content">
        <button @click="() => {
          const mdc = convert_md()
          const fp = export_info.export_path + '/' + export_info.filename + '.md'
          wss({
            req: 'save',
            path: fp,
            data: mdc
          })
            .then(socket => {
              if (!socket.msg.code) {
                msg({
                  text: `\`${export_info.filename + '.md'}\` 导出成功`
                })

                if (locate_exported) locate_file(fp)
              }
            })


        }">导出为md</button>

        <button @click="() => {
          const fp = export_info.export_path + '/' + export_info.filename + '.pdf'
          wss({
            req: 'convert',
            target: 'pdf',
            input: convert_md('pdf'),
            export_path: fp
          })
            .then(socket => {
              console.log(socket.msg)
              if (!socket.msg.code) {
                if (!socket.msg.msg.code) {
                  msg({
                    text: 'pdf导出成功'
                  })

                  if (locate_exported) locate_file(fp)
                } else {
                  msg({
                    text: '导出失败'
                  })
                }
              }
            })
        }">导出为pdf</button>
        <button @click="() => {
          const fp = export_info.export_path + '/' + export_info.filename + '.png'
          wss({
            req: 'convert',
            target: 'img',
            input: convert_md('pdf'),
            export_path: fp
          })
            .then(socket => {
              console.log(socket.msg)
              if (!socket.msg.code) {
                if (!socket.msg.msg.code) {
                  msg({
                    text: '图片导出成功'
                  })

                  if (locate_exported) locate_file(fp)
                } else {
                  msg({
                    text: '导出失败'
                  })
                }
              }
            })
        }">导出为图片</button>
        <button @click="() => {
          const content = convert_md('pdf')


          if (readyMdBy_typora) {
            keep_waiting()
            wss({
              req: 'md_preview',
              data: content
            })
              .then(socket => {
                // msg({
                //   text: JSON.stringify(socket.msg)
                // })
                stop_waiting()
              })
          } else {
            win_preview(markdown.parse(content))
          }

        }">预览md</button>
        <div class="checkbox">
          <input type="checkbox" :checked="readyMdBy_typora" @change="e => {
            readyMdBy_typora = e.target.checked
          }"> <span @click="e => e.target.previousElementSibling.click()">使用typora预览</span>
        </div>
        <div class="checkbox">
          <input type="checkbox" :checked="locate_exported" @change="e => {
            locate_exported = e.target.checked
          }"> <span @click="e => e.target.previousElementSibling.click()">导出后打开文件位置</span>
        </div>
      </div>
      <div class="option_content">
        <button @click="() => trans_baidu_all()">使用百度翻译</button>

        <div class="checkbox">
          <input type="checkbox" :checked="baidu_trans_force" @change="e => {
            baidu_trans_force = e.target.checked
          }"> <span @click="e => e.target.previousElementSibling.click()">覆盖旧翻译</span>
        </div>
        <button @click="() => {
          wordList.forEach(e => {
            delete e.trans
          })
        }">删除已存在翻译</button>

        <button v-if="transing" @click="() => {
          transing = false
          trans_stop = true

        }">停止翻译</button>
      </div>

      <div class="option_content" v-if="baidu_process">
        <div class="process_bar_wrap">
          <span>百度翻译</span>
          <div class="process_bar">
            <div :class="'process_current ' + (baidu_process / wordList.length == 1 ? 'process_done' : '')"
              :style="'width:' + baidu_process / wordList.length * 100 + '%'"></div>
          </div>
        </div>
      </div>

      <!-- <div class="option_content">
        <span>默写</span>
        <div class="checkbox">
          <input type="checkbox" :checked="dictation_mode == 'word'" @change="e => {
            dictation_mode = e.target.checked ? 'word' : null
          }"> <span @click="e => e.target.previousElementSibling.click()">根据词汇</span>
        </div>
        <div class="checkbox">
          <input type="checkbox" :checked="dictation_mode == 'mean'" @change="e => {
            dictation_mode = e.target.checked ? 'mean' : null
          }"> <span @click="e => e.target.previousElementSibling.click()">根据释义</span>
        </div>
        <div class="checkbox" v-if="dictation_mode">
          <input type="checkbox" @change="e => {
          }"> <span @click="e => e.target.previousElementSibling.click()">显示读音</span>
        </div>
        <button v-if="dictation_mode">批改</button>
        <div class="checkbox" v-if="dictation_mode">
          <input type="checkbox" @change="e => {
          }"> <span @click="e => e.target.previousElementSibling.click()">实时批改</span>
        </div>
      </div> -->

      <div class="option_content">
        <button @click="() => {
          wss({
            req: 'selet_single_exe',
            filename: 'Typora'
          })
            .then(socket => {
              if (socket.msg.code) {
                msg({
                  text: '地址获取失败！！！'
                })
                if (socket.msg.code == 1) {
                  msg({
                    text: '不是 typora 可执行文件'
                  })
                }
              } else {
                if (socket.msg.msg.length) {
                  typora_path_temp = socket.msg.msg
                } else {
                  msg({
                    text: '未选择文件'
                  })
                }
              }
            })
        }">选择typora位置</button>
        <input type="text" :value="typora_path_temp" disabled>
        <button ref="alter_typora_path" v-if="typora_path != typora_path_temp" @click="alter_tp">修改</button>
        <button @click="() => {
          wss({
            req: 'typora_path'
          })
            .then(socket => {
              console.log(socket.msg.msg);

              wss({
                req: 'file',
                type: 'go',
                path: socket.msg.msg
              })
                .then(res => {
                  console.log(res.msg.msg);

                })
            })
        }">打开typora位置</button>

        <div class="checkbox">
          <input type="checkbox" :checked="transWin_withMdEdit" @change="e => {
            transWin_withMdEdit = e.target.checked
          }"> <span @click="e => e.target.previousElementSibling.click()">编辑时打开翻译小窗</span>
        </div>
      </div>
      <div class="option_content">
        <button @click="() => {
          wss({
            req: 'md_temp_path'
          })
            .then(socket => {
              wss({
                req: 'path',
                type: 'go',
                path: socket.msg.msg
              })
            })
        }">打开临时文件位置</button>
        <div class="checkbox">
          <input type="checkbox" :checked="leave_md_temp" @change="e => {
            leave_md_temp = e.target.checked
          }"> <span @click="e => e.target.previousElementSibling.click()">保留临时文件</span>
        </div>

        <button @click="() => {
          wss({ req: 'del_md_temp' })
            .then(socket => {
              if (!socket.msg.code) {
                msg({
                  text: '临时文件已清空'
                })
              } else {
                msg({
                  text: '临时文件清空失败！！！'
                })
              }
            })
        }">删除临时文件</button>
      </div>
      <!-- <div class="option_content">
        <button>- 获取所有星标</button>
      </div> -->
      <div v-if="baidu_process_err">错误: <span>{{ baidu_process_err }}</span></div>
    </div>
  </div>
  <div v-if="data_list && Object.keys(data_list).length" id="data_list" ref="data_list"
    :class="'wrapper ' + (fixed_wrap == 'data_list' ? 'fixed' : '')">
    <div class="fixed_switch" v-html="icon.sticky" @click="switch_fixed_wrap"></div>
    <ul v-for="(v, k)  in data_list">
      <li v-if="k.length" :class="'item_group ' + (v.s.current ? 'group_current' : '')" @click="() => {
        v.s.show = !v.s.show

        // data_list[k].forEach(e => {
        //   if (e.group == k && e.data) {
        //     e._stat.s = v.sh
        //   }
        // })
      }">
        <div>
          <div class="content">
            <span v-html="(v.s.show ? '∨' : '>') + ' '"></span>
            <span>{{ k }}</span>
          </div>

          <div class="btns_wrap" @click="e => e.stopPropagation()">
            <span class="del_file" @click="e => {
              e.stopPropagation()
              e.target.querySelector('.ensure_wrap').style.display = 'flex'

              const first_split = k.indexOf('/'),
                last_split = k.lastIndexOf('/')
              v.root = first_split == -1 ? k : k.substr(0, first_split)
              v.par = last_split == -1 ? k : k.substr(last_split + 1)

            }">删除文件夹<div class="ensure_wrap" @click="e => {
              e.stopPropagation()
              e.target.closest('.ensure_wrap').style.display = 'none'
            }">
                <span class="btn_dangerous" @click="() => {
                  const del_dir = export_info.export_path + '/' + v.root
                  wss({
                    req: 'path',
                    type: 'del',
                    path: del_dir
                  })
                    .then(socket => {
                      read_dir()
                      if (!socket.msg.code) {
                        msg({
                          text: `\`${del_dir}\` 已删除`
                        })
                      }
                    })

                  // data_list.splice(data_list.indexOf(v), 1)
                }">确认删除 /{{ v.root }}</span>
                <span v-if="v.root != v.par" class="btn_dangerous" @click="() => {
                  const del_dir = export_info.export_path + '/' + k
                  wss({
                    req: 'path',
                    type: 'del',
                    path: del_dir
                  })
                    .then(socket => {
                      read_dir()
                      if (!socket.msg.code) {
                        msg({
                          text: `\`${del_dir}\` 已删除`
                        })
                      }
                    })

                  // data_list.splice(data_list.indexOf(v), 1)
                }">确认删除 /{{ v.par }}</span>
                <span>取消</span>
              </div>
            </span>
          </div>
        </div>
      </li>
      <li v-for="val in v.d"
        :class="'data_item ' + (val.data && k.length ? 'sub_item ' : ' ') + (val.current ? 'current' : '')" @click="e => {
          set_current(val)

          // set_data(val.data, val.virtual)
        }" :title="(val.data ? '' : '点击切换子元素显示')">
        <div v-if="val.data && (v.s.show || !k.length)">
          <div>
            <span><b>{{ val.filename }}</b></span>
            <span v-if="!val.virtual"><span class="desc">文件大小:</span> {{ val.stat.size }} 字节</span>
            <span><span><span class="desc">count:</span> {{ val.data.length }}</span></span>
            <div v-if="!val.virtual">
              <span><span class="desc">创建时间:</span> {{ read_timestamp(val.stat.ctime) }}</span>
              <span><span class="desc">修改时间:</span> {{ read_timestamp(val.stat.mtime) }}</span>
              <span><span class="desc">访问时间:</span> {{ read_timestamp(val.stat.atime) }}</span>
            </div>
          </div>
          <div v-if="!val.virtual" class="btns_wrap" @click="e => e.stopPropagation()">
            <!-- <span class="">使用 VS Code 编辑</span> -->
            <span @click="() => {
              wss({ req: 'file', type: 'go', path: val.path })
                .then(res => console.log(res))
            }">打开文件位置</span>
            <span class="del_file" @click="e => {
              e.stopPropagation()
              e.target.querySelector('.ensure_wrap').style.display = 'flex'

            }">删除<div class="ensure_wrap" @click="e => {
              e.stopPropagation()
              e.target.closest('.ensure_wrap').style.display = 'none'
            }">
                <span class="btn_dangerous" @click="() => {
                  wss({
                    req: 'file',
                    type: 'del',
                    path: val.path
                  })
                    .then(socket => read_dir())

                  // data_list.splice(data_list.indexOf(val), 1)
                }">确认</span>
                <span>取消</span>
              </div>
            </span>
          </div>
        </div>
      </li>
    </ul>
  </div>
  <div id="wrap" ref="wrap" :class="'wrapper ' + (fixed_wrap == 'wrap' ? 'fixed' : '')">
    <div class="fixed_switch" v-html="icon.sticky" @click="switch_fixed_wrap"></div>
    <div id="ctrl_wrap">
      <div>
        <button @click="() => {
          wordList = []
          wordSet = {}
        }">清空</button>
        <input type="file" @change="read_json" ref="json_input" style="display: none;">
        <button @click="() => {
          this.$refs.json_input.click()
        }" title="Ctrl + O">导入json</button>

        <input type="text" class="export_filename" placeholder="导出的json文件名" :value="export_info.filename" @input="event => {
          export_info.filename = event.target.value
        }" ref="json_filename">
        <button @click="export_json" title="聚焦文本框 + Enter || Ctrl + S">导出json</button>
        <input type="checkbox" @change="e => {
          export_info.addTime = e.target.checked
        }"> <span @click="e => e.target.previousElementSibling.click()">时间后缀</span>
      </div>
      <div id="cbox_wrap">
        <div>
          <input type="checkbox" :checked="title_case" @change="e => {
            title_case = e.target.checked
          }"> <span @click="e => e.target.previousElementSibling.click()">首字母大写</span>
        </div>
        <div>
          <input type="checkbox" @change="e => {
            readOnly = e.target.checked
          }"> <span @click="e => e.target.previousElementSibling.click()">只读</span>
        </div>
        <div>
          <input type="checkbox" @change="e => {
            t_link = e.target.checked
          }"> <span @click="e => e.target.previousElementSibling.click()">跳转链接</span>
        </div>
        <div>
          <input type="checkbox" :checked="note_show" @change="e => {
            note_show = e.target.checked
          }"> <span @click="e => e.target.previousElementSibling.click()">显示笔记</span>
        </div>
        <div>
          <input type="checkbox" checked :checked="baiduTrans_show" @change="e => {
            baiduTrans_show = e.target.checked
          }"> <span @click="e => e.target.previousElementSibling.click()">显示百度翻译</span>
        </div>
      </div>
      <div v-if="!readOnly">
        <button @click="() => {
          wordList = mixArr(wordList)
          mixed = true
        }">乱序</button>
        <button @click="() => {
          wordList = reverseArr(wordList)
          mixed = true
        }">倒序</button>
        <button @click="() => {
          // wordList = reverseArr(wordList)
          wordList.sort((a, b) => {
            if (a.text < b.text) return character_ascent ? -1 : 1;
            if (a.text > b.text) return character_ascent ? 1 : -1;
            return 0;
          })
          mixed = true
        }">按字符排序</button>
        <div class="checkbox">
          <input type="checkbox" checked :checked="character_ascent" @change="e => {
            character_ascent = e.target.checked
          }"> <span @click="e => e.target.previousElementSibling.click()">字符升序</span>
        </div>
        <button v-if="mixed" @click="() => {
          wordList = order_arr()

          mixed = false
          reversed = false
        }">正序</button>
      </div>
      <div v-if="!readOnly">
        <!-- 默写 -->
        <button @click="toggle_rw" v-if="!dictation_mode">{{ wr_t[rw_flag ? 1 : 0] }}</button>

        <!-- 批改 -->
        <button @click="toggle_rst" v-if="rw_flag" v-text="sr_t[sr_flag ? 1 : 0]"></button>
        <button @click="toggle_rst_i" v-if="sr_flag">{{ sr_t_i[sr_flag_instant ? 1 : 0] }}</button>

        <button @click="() => {
          wordList.forEach(e => {
            delete e.stat.uipt
            e.stat.correct = {}
          })
        }" v-if="rw_flag">重做</button>

        <span v-if="rw_flag">
          <input type="checkbox" @change="e => {
            case_determination = e.target.checked
            correctAll()
          }"> <span @click="e => e.target.previousElementSibling.click()">大小写判定</span>
        </span>
      </div>
    </div>

    <div id="add_wrap" v-if="!readOnly">
      词汇: <input type="text" ref="word" placeholder="F 键聚焦">
      释义: <input type="text" ref="mean" placeholder="支持 md 语法">
      <button @click="add" ref="addWord" title="聚焦文本框 + Enter" tabindex="-1">添加</button>
      <p :style="'color:' + add_msg.color">{{ add_msg.msg }}</p>
    </div>

    <div>
      <button v-if="wss" @click="() => {
        const temp = {
          md: '在此添加笔记…',
          index: wordList.length
        }

        // 等待过程中不能有任何消息往来
        waiting = true
        auto_save_t = auto_save
        auto_save = false

        wss({ req: 'md_edit', data: temp.md, word: 'temp', leave_temp: leave_md_temp })
          .then(socket => {
            if (!socket.msg.code) {
              const receive = socket.msg.msg.content
              if (receive.trim().length && receive.trim() != temp.md) {
                temp.md = receive
                msg({
                  text: '成功添加笔记'
                })

                if (reversed) {
                  wordList = [temp, ...wordList]
                } else {
                  wordList.push(temp)
                }
              } else {
                msg({
                  text: '未添加笔记'
                })
              }

              msg({
                text: '`typora` 退出码: ' + socket.msg.msg.code
              })

              // 节点自动保存
              if (auto_key_save) ws_save()
            } else {
              msg({
                text: JSON.stringify(socket.msg)
              })

              if (socket.msg.code == 100) {
                msg({
                  text: '3秒后打开 `typora` 官网',
                  delay: 3000
                }).then(() => open('https://typoraio.cn'))
              }
            }

            // console.log(md.parse(socket.msg.msg));
            waiting = false
            auto_save = auto_save_t
          })
      }" ref="addNote">使用typora添加纯笔记</button>
    </div>
  </div>
  <ul id="contnet_wrap" :class="'wrapper ' + (fixed_wrap == 'contnet_wrap' ? 'fixed' : '')">
    <li v-for="(obj, index) in wordList" :id="obj.text + obj.index"
      :class="'word_wrap ' + (obj.star ? 'collected ' : ' ') + (sr_flag && obj.stat ? obj.stat.correct.elemClass ? obj.stat.correct.elemClass : obj.stat.correct.rstelemInstantClass : '')">

      <div v-if="obj.from" class="item_from" @click="() => {
        data_list[obj.from[0]].d.forEach(e => {
          if (e.filename == obj.from[1]) {
            // set_data(e.data)
            set_current({
              filename: obj.from[1],
              group: obj.from[0],
              virtual: obj.virtual
            })

            this.$nextTick(() => {
              scroll_to(obj.text + obj.oIndex)
            })
          }
        })

      }">
        <span>{{ obj.from.join('/') }}</span>
      </div>

      <div class="trans_baidu" @mouseenter="e => {
        // $(e.target).css({
        //   height: $(e.target).find('.content').outerHeight() + 'px'
        // })

        e.target.style.height = e.target.querySelector('.content').getBoundingClientRect().height + 'px'


        // $(e.target).siblings('.block').stop().css({
        //   whiteSpace: 'pre'
        // }).animate({
        //   width: $(e.target.closest('.trans_baidu')).width() - $(e.target).find('.content').outerWidth() + 'px'
        // })

      }" @mouseleave="e => {
        // e.style.height = $(e.target.closest('.word_wrap').querySelector('.block')).outerHeight() + 'px'
        e.target.style.height = '3rem'

        // $(e.target).siblings('.block').stop().css({
        //   whiteSpace: 'normal',
        //   width: 'auto'
        // })
      }" v-if="obj.text && baiduTrans_show && obj.trans?.baidu && !rw_flag">
        <h2 class="icon_wrap" v-html="icon.baidu" @click="open('https://fanyi.baidu.com/#en/zh/' + obj.text)"
          title="打开百度"></h2>
        <!-- 百度翻译 -->
        <div class="content" v-if="obj.trans.baidu">
          <div class="mean_wrap">
            <div v-for="val, key in obj.trans.baidu.mean.mean">
              <span class="w_pre">{{ val.pre }}</span>
              <ul>
                <li v-for="v in val.cont"><span>{{ v }}</span></li>
              </ul>
            </div>
          </div>
          <div class="voice_wrap">
            <ul>
              <li v-for="val, key in obj.trans.baidu.mean.voice" v-if="obj.trans.baidu.mean.voice">
                <span>{{ key }}:</span>
                <span class="voice" @click="e => e.target.closest('.voice').querySelector('audio').play()">
                  <span>{{ val }}</span>
                  <span v-if="obj.trans.baidu.aud?.[key]">
                    <span class="svg" v-html="icon.audPlay"></span>
                    <audio :src="obj.trans.baidu.aud[key]"></audio>
                  </span>
                </span>
              </li>
            </ul>
          </div>
          <div class="aud_wrap">
            <h3>{{ obj.text }}</h3>
            <div>
              <span v-for="val, key in obj.trans.baidu.aud" class="aud_item" @click="e => {
                e.target.closest('.aud_item').querySelector('audio').play()
              }">
                <span class="lang_type">{{ key }}</span> <span class="svg" v-html="icon.audPlay"></span><audio
                  :src="val"></audio>
              </span>
            </div>
          </div>
        </div>
      </div>
      <div class="block" v-if="obj.text">
        <div>
          <div class="word" @contextmenu="e => {
            e.preventDefault()

            console.log(obj.trans.baidu);

            // trans.baidu(obj.text)
            //   .then(data => {
            //     console.log(data);
            //   })

            wss({
              req: 'api',
              query: 'baidu',
              data: obj.text
            }).then(socket => {
              console.log(socket.msg.msg);
            })
          }">
            <!-- 星标 -->
            <span v-html="icon.star" :class="'star ' + (obj.star ? 'starred' : '')" @click="() => {
              obj.star = !obj.star

              if (obj.star) obj.starTime = Date.now()
            }"></span>
            <h2 v-if="!obj.stat.h" class="word_text" @dblclick="event => {
              if (!readOnly) {
                toggle_rw_c(index)
                rw_flag = true
              }
              // console.log(event.target.nextElementSibling)
              // event.target.parentNode.querySelector('input.word_user').focus()
            }">{{ (title_case ? obj.text[0].toUpperCase() + obj.text.slice(1) : obj.text) }}</h2>
            <input :tabindex="(index + 1)" class="word_user" type="text" :value="(obj.stat.uipt ?? '')"
              v-if="obj.stat.h" @input="event => {
                obj.stat.uipt = event.target.value
                correct(obj)
              }" @keyup="event => {
                if (event.key == 'Escape') {
                  delete obj.stat.h
                  rw_c_recover()
                } else if (event.key == 'Enter') {
                  // 批改当前
                  correct(obj)

                  sr_flag = true
                  obj.stat.correct.elemClass = obj.stat.correct.rstelemInstantClass
                }
              }">
            <button class="include_btn" v-if="obj.stat.h" @click="() => {
              delete obj.stat.h
              rw_c_recover()
            }" title="聚焦文本框 + Esc" tabindex="-1">显示答案</button>
            <button class="include_btn" v-if="obj.stat.h" @click="() => {
              if (obj.stat.uipt?.length) {
                obj.text = obj.stat.uipt

                // 节点自动保存
                if (auto_key_save) this.$refs.wss_export.click()
              }
              delete obj.stat.h
              rw_c_recover()
            }" tabindex="-1">修改</button>
          </div>

          <div class="audio_wrap" v-if="obj.trans?.baidu">
            <span v-for="val, key in obj.trans.baidu.aud" class="aud_item"
              @click="e => e.target.closest('.aud_item').querySelector('audio').play()">
              <span class="lang_type">{{ key }}</span>
              <span class="svg" v-html="icon.audPlay"></span>
              <audio :src="val"></audio>
            </span>
          </div>
          <div class="mean">
            <span class="desc">释义：</span>
            <span class="mean_text" v-if="!obj.alter" @dblclick="e => {
              if (!readOnly) {
                obj.alter = true
              }
            }" v-html="md_text(obj.mean)"></span>
            <span v-if="obj.alter">
              <input type="text" :value="obj.mean" @input="e => {
                obj.TEMP_mean = e.target.value
              }" @keyup="e => {
                if (e.key == 'Enter') {
                  if (obj.TEMP_mean?.length) {
                    obj.mean = obj.TEMP_mean

                    // 节点自动保存
                    if (auto_key_save) this.$refs.wss_export.click()
                  }
                  delete obj.alter
                } else if (e.key == 'Escape') {
                  delete obj.alter
                }
              }">
              <button @click="e => {
                if (obj.TEMP_mean?.length) {
                  obj.mean = obj.TEMP_mean

                  // 节点自动保存
                  if (auto_key_save) this.$refs.wss_export.click()
                }
                delete obj.alter
              }" title="聚焦文本框 + Enter">完成修改</button>
              <button @click="() => {
                delete obj.alter
              }" title="聚焦文本框 + Esc">放弃修改</button>
            </span>
          </div>
          <div class="trans_wrap" v-if="t_link">
            <span class="item t_youdao" @click="open(`https://youdao.com/result?word=${obj.text}&lang=en`)">转到网易</span>
            <span class="item t_bing" @click="open('https://cn.bing.com/dict/search?q=' + obj.text)">转到bing</span>
          </div>
        </div>
        <div v-if="!readOnly" class="ctrls">
          <span class="word_del" @click="del_word(index)">删除</span>
        </div>
      </div>

      <div class="note_wrap" v-if="note_show">
        <div class="mdEdit_wrap">
          <!-- <textarea name="" id="" @input="e => {
                obj.md = e.target.value
                console.log(md.parse(obj.md));

              }"></textarea> -->

          <div class="ctrls">
            <!-- 星标 -->
            <span v-if="!obj.text" v-html="icon.star" :class="'star ' + (obj.star ? 'starred' : '')" @click="() => {
              obj.star = !obj.star

              if (obj.star) obj.starTime = Date.now()
            }"></span>
            <button @click="event => {
              const word = obj.text ?? 'temp'

              if (transWin_withMdEdit && obj.text) open('https://fanyi.baidu.com/#en/zh/' + obj.text)

              // 等待过程中不能有任何消息往来
              keep_waiting()

              wss({ req: 'md_edit', data: (obj.md ? obj.md : `# ${obj.text} 的笔记\n\n> 关闭该页面以保存\n\n<font color=red>**注**：请不要打开多个typora实例！！！</font>\n\n<font color=#dbb300>如连接中断，可刷新页面后在临时文件中找回数据</font>\n\n`), word: word, leave_temp: leave_md_temp })
                .then(socket => {
                  if (!socket.msg.code) {
                    if ((socket.msg.msg.content).trim().length) {
                      obj.md = socket.msg.msg.content
                      msg({
                        text: word + ' 的笔记已修改'
                      })
                    } else {
                      delete obj.md
                      msg({
                        text: word + ' 的笔记已删除'
                      })

                      if (!obj.text) {
                        const ci = obj.index
                        wordList.splice(obj.index, 1)

                        wordList.forEach(e => {
                          if (e.index > ci) e.index--
                        })

                      }
                    }

                    msg({
                      text: '`typora` 退出码: ' + socket.msg.msg.code
                    })

                    // 节点自动保存
                    if (auto_key_save) ws_save()
                  } else {
                    msg({
                      text: JSON.stringify(socket.msg)
                    })

                    if (socket.msg.code == 100) {
                      msg({
                        text: '3秒后打开 `typora` 官网',
                        delay: 3000
                      }).then(() => open('https://typoraio.cn'))
                    }
                  }

                  stop_waiting()
                })
            }" v-if="wss && !readOnly">使用typora编辑笔记</button>
          </div>
        </div>
        <!-- <div v-if="obj.md" v-html="md.parse(obj.md)"></div> -->
        <md :mdt="obj.md" v-if="obj.md" />
      </div>
    </li>
  </ul>
</template>

<script>
import { reactive } from 'vue';

import { ws } from '@/modules/websocket'
import { icons } from '@/assets/icons'
import transapi from '@/modules/transapi'
import { msg } from '@/modules/fns.js'

import { marked } from 'marked'
import $ from 'jquery'

import md from '@/component/md.vue'

const global_config = {
  icon: icons,
  markdown: marked,
  msg: msg,

  // 是否正在使用本地配置
  conf_local: false,

  // 首字母大写
  title_case: true,
  // 当前置顶
  fixed_wrap: 'ws_wrap',

  // 自动保存
  auto_save: true,
  auto_key_save: true,
  auto_save_dur: 3,
  auto_save_safest: false,

  // 编辑md时打开翻译小窗
  transWin_withMdEdit: false,

  // 保留md临时文件
  leave_md_temp: true,

  typora_path_temp: '',
  typora_path: '',

  // 默写模式
  dictation_mode: null,

  newWin_size: {
    w: 800,
    h: 400
  },

  wordList: reactive([]),
  wordSet: {},

  wr_t: ['默写', '查看'],
  sr_t: ['批改', '取消批改'],
  sr_t_i: ['实时批改', '取消实时批改'],

  export_info: {
    filename: 'data',
    addTime: false,
    key_data_only: false,
    extend_name: '',
    export_path: './export/'
  },

  // 使用typora预览
  readyMdBy_typora: true,
  // 导出md后打开位置
  locate_exported: true,

  case_determination: false,

  t_link: false,
  readOnly: false,

  // 读 or 写
  rw_flag: false,
  // 批改
  sr_flag: false,
  // 实时批改
  sr_flag_instant: true,

  // 
  add_msg: {
    color: 'red'
  },

  wss: null,
  wsp: 0,

  data_list: null,

  // 乱序
  mixed: false,
  // 倒序
  reversed: false,
  // 字符升序
  character_ascent: true,

  trans: transapi,

  baidu_process: 0,
  baidu_process_err: 0,
  // 覆盖旧翻译
  baidu_trans_force: false,
  baiduTrans_show: true,

  // 停止翻译
  trans_stop: false,
  transing: false,

  waiting: false,
  note_show: true,
}

export default {
  components: {
    md
  },
  data() {
    return global_config
  },
  watch: {
    auto_save: {
      handler(n, o) {
        if (n) {
          clearInterval(window.ws_auto_save)
          window.ws_auto_save = setInterval(() => this.$refs.wss_export.click(), this.auto_save_dur * 60000)
        } else {
          clearInterval(window.ws_auto_save)
        }
      },
      immediate: true
    },

    typora_path: {
      handler(n, o) {
        localStorage.setItem('typora_path', n)
      }
    }
    // wordList: {
    //   handler(n, o) {

    //     // 响应式保存
    //     if (this.auto_save_safest) {
    //       this.$refs.wss_export.click()
    //     }
    //   }
    // }
  },
  mounted() {
    this.get_ls_dataList()

    const url_search = new URLSearchParams(location.search)
    this.wsp = url_search.get('ws_port') ?? 0
    this.handshake()

    this.$refs.word.focus()

    window.addEventListener('keydown', event => {
      if (event.ctrlKey) {
        if (event.key == 'O' || event.key == 'o') {
          event.preventDefault();
          this.$refs.json_input.click()
        } else if (event.key == 'S' || event.key == 's') {
          event.preventDefault();
          this.export_json()
        }
      }

      // ws导出
      if (event.altKey && (event.key == 'S' || event.key == 's')) {
        event.preventDefault()
        this.$refs.wss_export.click()
      }
    })

    window.addEventListener('keyup', event => {
      const key = event.key

      if (event.target.nodeName != 'INPUT') {
        if (Number(key) == key) {

          const fwl = [
            '',
            'ws_wrap',
            'data_list',
            'wrap'
          ]

          if (fwl[key]) this.fixed_wrap = this.fixed_wrap == fwl[key] ? null : fwl[key]
        } else {
          switch (key.toLowerCase()) {
            case 'f':
              this.$refs.word.focus()
              break;

            default:
              break;
          }
        }
      } else {
        switch (key.toLowerCase()) {
          case 'enter':
            if (this.$refs.word == document.activeElement || this.$refs.mean == document.activeElement) {
              this.$refs.addWord.click()
            } else if (this.$refs.json_filename == document.activeElement) {
              this.export_json()
            }
            break;

          default:
            break;
        }
      }
    })

    document.addEventListener('click', e => {
      $('.ensure_wrap').hide()
    })
  },
  // watch: {
  //   baidu_process(newVal, oldVal) {
  //     console.log(newVal, oldVal);
  //   }
  // },
  methods: {
    scroll_to(id) {
      const y = document.querySelector('#' + id).getBoundingClientRect().top + window.pageYOffset
      // + this.fixed_wrap ? document.querySelector('#' + this.fixed_wrap).getBoundingClientRect().height : 0
      const elem = this.$refs[this.fixed_wrap]
      if (elem) elem.style.opacity = 0

      scrollTo(0, y)

      if (elem) setTimeout(() => {
        elem.style.opacity = 1
      }, 1000)
    },
    // 获取全局设置
    getThis() {
      return JSON.parse(JSON.stringify(global_config))
    },

    split_str(data, splitLen = 1024) {
      const arr = []

      const len = Math.floor(data.length / splitLen)

      for (let i = 0; i <= len; i++) {
        arr.push(data.substr(0, splitLen))
        data = data.slice(splitLen)
      }

      return arr
    },

    keep_waiting() {
      this.waiting = true
      this.auto_save_t = this.auto_save
      this.auto_save = false
    },
    stop_waiting() {
      this.waiting = false
      this.auto_save = this.auto_save_t
    },

    save_settings_split(arr, path, firstTime, callback) {
      const data = arr.shift()
      if (data) {
        this.wss({
          req: 'write',
          flag: firstTime ? 'w' : 'a',
          data: data,
          path: path
        }).then(socket => {
          if (!socket.msg.code) {
            this.save_settings_split(arr, path, null, callback)
          } else {
            callback && callback()
            this.stop_waiting()
            msg('保存失败')
          }
        })
      } else {
        msg('保存成功')
        callback && callback(1)
        this.stop_waiting()
      }
    },
    // 定位文件位置
    locate_file(fp) {
      this.wss({
        req: 'path',
        type: 'abs',
        path: fp
      }).then(soc => {
        if (!soc.msg.code) {

          this.wss({
            req: 'file',
            type: 'go',
            path: soc.msg.msg
          })
        }
      })
    },
    // 转为md
    convert_md(type) {
      let content = '# ' + this.export_info.filename + (type ? '' : '\n\n[toc]') + '\n\n'

      this.wordList.forEach((elem, i) => {
        if (elem.text) {
          content += `## ${elem.text[0].toUpperCase() + elem.text.slice(1)}\n\n`

          const voice = elem.trans?.baidu?.mean?.voice
          if (voice) {
            content += '**读音：** '
            for (let k in voice) {
              content += `\`${k}\`: ${voice[k]}  `
            }
            content = content.trim() + '\n\n'
          }
          content += `**释义：** ${elem.mean}\n\n`
        }

        if (elem.md) content += (elem.md.trim() + '\n\n')


        if (i != this.wordList.length - 1) content += '\n\n---\n\n\n\n'
      })

      return content
    },
    switch_fixed_wrap(e) {
      const current_id = e.target.closest('.wrapper').id

      if (this.fixed_wrap == current_id) {
        this.fixed_wrap = ''
      } else {
        this.fixed_wrap = current_id
      }
    },
    alter_tp() {
      this.wss({ req: 'alter_typora_path', path: this.typora_path_temp })
        .then(socket => {
          console.log(socket.msg.msg);

          if (!socket.msg.code) {
            this.typora_path = this.typora_path_temp

            msg({
              text: '`typora`路径更改成功'
            })
          }

        })
    },
    md_text(str) {
      return marked.parse(str)
    },
    trans_baidu_all(index = 0) {
      if (!index) {
        this.baidu_process = 0
        this.baidu_process_err = 0
        this.trans_stop = false
        this.transing = true
      }

      if (!this.baidu_trans_force && this.wordList[index]?.trans?.baidu) {
        this.baidu_process++
        if (this.wordList[index + 1]) this.trans_baidu_all(index + 1)
      } else {
        if (this.wordList[index]?.text) {
          this.wss({
            req: 'api',
            query: 'baidu',
            data: this.wordList[index].text
          }).then(socket => {
            if (socket.msg.code) {
              this.baidu_process_err++
            } else {
              if (!this.wordList[index].trans) this.wordList[index].trans = {}

              const nor_mean = this.normalize_baidu_trans(socket.msg.msg.mean)
              if (nor_mean) {
                this.wordList[index].trans.baidu = {
                  aud: socket.msg.msg.aud,
                  mean: nor_mean
                }
              }

              // 节点自动保存
              if (this.auto_key_save) this.$refs.wss_export.click()

              // console.log(this.wordList[index].trans.baidu)

              this.baidu_process++
            }
          })
        } else {
          this.transing = false
          this.baidu_process++
        }

        const tout = 2000

        setTimeout(() => {
          if (this.trans_stop) {
            msg({
              text: '翻译结束'
            })
            this.transing = false
          } else {
            if (this.wordList[index + 1]) {
              // 如果后面还有
              this.trans_baidu_all(index + 1)
            } else {
              console.log('循环完毕');
              // 如果有报错，重新循环
              this.baidu_trans_force = false
              if (this.baidu_process_err) this.trans_baidu_all()
            }
          }
        }, tout)
      }
    },

    normalize_baidu_trans(obj) {
      // console.log(obj);
      let exp_obj = {}

      try {
        obj.content ? (() => {
          obj.content[0].mean.forEach(e => {
            e.cont = Object.keys(e.cont)
          })

          let _voice = {}
          if (obj.voice) obj.voice.forEach(v => {
            let k = Object.keys(v)[0].replace('_phonic', '')
            switch (k) {
              case 'en':
                k = 'uk'
                break;
              case 'us':
                k = 'en'
                break
            }
            _voice[k] = Object.values(v)[0]
          })

          exp_obj = {
            mean: obj.content[0].mean,
            voice: _voice
          }
        })() :
          (() => {
            exp_obj = {
              mean: [{ cont: [obj.data[0].dst], pre: '' }]
            }
          })()
      } catch (err) {
        console.error(err);
        msg({
          text: `<font color=#e06c6c>${err}</font>`,
          title: 'Error'
        })
        this.baidu_process_err++

        return 0
      }

      // console.log(JSON.parse(JSON.stringify(exp_obj)));
      return JSON.parse(JSON.stringify(exp_obj))
    },


    resolve_fileList(temp, lastDir = '') {
      const resolve_arr = []

      for (let k in temp) {
        if (temp[k].data) {
          // 是文件
          // resolve_arr.push({ ...temp[k], filename: k })
          resolve_arr.push({ ...temp[k], filename: k, group: lastDir })
        } else {
          // 是文件夹
          const dir = (lastDir.length ? lastDir + '/' : '') + k
          // resolve_arr.push({ group: dir })
          resolve_arr.push(...this.resolve_fileList(temp[k], dir))
        }
      }

      return resolve_arr
    },
    read_dir() {
      return new Promise(resolve => {
        this.wss({ req: 'file', type: 'jsons', path: this.export_info.export_path })
          .then(socket => {
            if (!socket.msg.code) {
              const resolve_arr = this.resolve_fileList(JSON.parse((JSON.parse(socket.msg.msg))))


              // const new_obj = {}

              const od = JSON.parse(JSON.stringify(this.data_list))

              this.data_list = {}


              const v_data = (group, name) => {
                this.data_list[group] = {
                  s: {},
                  d: [{
                    stat: {},
                    _stat: {},
                    filename: name,
                    group: group,
                    data: [],
                    virtual: true
                  }]
                }

                return {
                  push: (data, from) => {
                    const _data = JSON.parse(JSON.stringify(data))
                    _data.oIndex = _data.index
                    _data.index = this.data_list[group].d[0].data.length
                    _data.from = from
                    this.data_list[group].d[0].data.push(_data)
                  },
                  clear: () => {
                    if (!this.data_list[group].d[0].data.length) delete this.data_list[group]
                  }
                }
              }

              const all = v_data('汇总', 'all')
              const starred = v_data('收藏集', 'all')
              const mistakes = v_data('错题集', 'all')

              resolve_arr.forEach(e => {
                // if (!new_obj[e.group]) new_obj[e.group] = []
                // new_obj[e.group].push(e)


                if (!this.data_list[e.group]) this.data_list[e.group] = { s: {}, d: [] }

                try {
                  const ods = od?.[e.group]?.s

                  if (ods) this.data_list[e.group].s = ods
                } catch { }

                e._stat = {}

                e.data.forEach(item => {
                  if (!item?.virtual) {
                    const from = [e.group, e.filename]
                    if (item?.star) starred.push(item, from)
                    if (item?.stat?.correct?.rst == false) mistakes.push(item, from)
                    all.push(item, from)
                  }
                })

                this.data_list[e.group].d.push(e)

              })

              starred.clear()
              mistakes.clear()
              all.clear()


              // 读取文件夹保留先前状态
              // for (let k in this.data_list) {
              //   try {
              //     if (od[k]) od[k].forEach((e, i) => {
              //       if (this.data_list[k][i].filename = e.filename) this.data_list[k][i]._stat = e._stat
              //     })
              //   } catch { }
              // }

              console.log(this.data_list);

              msg('目录读取成功')

              // this.data_list = new_obj
            } else {
              msg({
                text: socket.msg.msg,
                title: '导出目录读取失败！'
              })
            }

            resolve()
          })
      })
    },

    init_conf() {
      return new Promise(resolve => {
        // 初始化设置
        this.wss({
          req: 'setting',
          type: 'read'
        })
          .then(socket => {
            if (!socket.msg.code) {
              try {
                const conf = JSON.parse(socket.msg.msg)

                for (let k in conf) {
                  this[k] = conf[k]
                }

                this.conf_local = true

                msg('全局配置解析成功')

              } catch (err) {
                msg('配置文件解析失败 ' + err)
              }
            } else {
              msg('配置文件解析失败 ' + socket.msg.msg)
            }

            resolve()
          })
      })
    },
    handshake() {
      // console.log(this.wsp);
      ws(this.wsp, { req: "handshake" })
        .then((socket) => {
          if (socket.msg.msg == 'ok') {
            this.waiting = false
            // 握手成功
            this.wss = socket.sender


            msg({
              text: '<font color=#86bc77>**WebSocket** 已连接</font>'
            })

            // if (window.closeTimer) {
            //   clearInterval(window.closeTimer)

            //   msg({
            //     text: '页面关闭计划已清除'
            //   })
            // }

            this.init_conf()
              .then(() => {
                socket.sender({
                  req: 'path',
                  type: 'abs',
                  path: this.export_info.export_path
                })
                  .then(res => {
                    this.export_info.export_path = res.msg.msg
                    this.read_dir()
                      .then(() => {
                        // typora地址 如果已更改
                        const tp = localStorage.getItem('typora_path')

                        if (tp) {
                          this.typora_path_temp = tp
                          this.typora_path = tp
                          this.alter_tp()
                        }
                      })
                  })
              })
          }

          socket.onclose = () => {
            this.wss = null

            msg({
              text: '<font color=#e06c75>websocket连接已断开</font>',
            })

            // msg({
            //   text: "websocket连接已断开 **5分钟** 后自动关闭该页"
            // })

            // let timeleave = 5
            // clearInterval(window.closeTimer)
            // window.closeTimer = setInterval(() => {
            //   timeleave--
            //   if (timeleave <= 0) {
            //     window.opener = null
            //     window.open('about:blank', '_top').close()
            //   } else {
            //     msg({
            //       text: `<font color=#e06c75>**${timeleave}分钟** 后自动关闭该页</font>`,
            //       title: '注意'
            //     })
            //   }
            // }, 60000)
            console.log('WebSocket连接已关闭')
          }
        })
    },
    add() {
      if (this.$refs.word.value && this.$refs.mean.value) {
        if (!this.wordSet[this.$refs.word.value]) {
          this.wordSet[this.$refs.word.value] = this.$refs.mean.value

          const temp = {
            text: this.$refs.word.value.trim(),
            mean: this.$refs.mean.value.trim(),
            stat: {
              correct: {}
            },
            index: this.wordList.length
          }

          if (this.reversed) {
            this.wordList = [temp, ...this.wordList]
            console.log(this.wordList);
          } else {
            this.wordList.push(temp)
          }

          this.$refs.word.value = ''
          this.$refs.mean.value = ''

          this.$refs.word.focus()

          this.add_msg.msg = ''

          // 节点自动保存
          if (this.auto_key_save) this.ws_save()
        } else {
          this.add_msg.msg = '输入有重复！'
        }
      } else {
        this.add_msg.msg = '请输入完整！'
      }

    },
    toggle_rw() {
      this.note_show = this.rw_flag
      if (this.rw_flag) this.sr_flag = false
      this.rw_flag = !this.rw_flag
      for (let i in this.wordList) {
        if (this.wordList[i].stat) this.wordList[i].stat.h = this.rw_flag
      }
    },
    show_rst() {
      this.wordList.forEach(e => {
        if (e.stat) e.stat.correct.elemClass = e.stat.correct.elemInstantClass
      })
    },
    toggle_rst() {
      if (this.sr_flag) this.show_rst()
      this.sr_flag = !this.sr_flag
    },
    toggle_rst_i() {
      this.show_rst()
      this.sr_flag_instant = !this.sr_flag_instant
    },
    toggle_rw_c(index) {
      try {
        this.wordList[index].stat.h = !this.wordList[index].stat.h;
      } catch { }
    },

    rw_c_recover() {
      // 如果全部没有隐藏
      try {
        this.wordList.forEach(e => {
          if (e.stat.h) throw ''
        })

        this.rw_flag = false
        this.sr_flag = false
      } catch { }
    },

    // 批改
    correct(obj) {
      if (obj.stat) {
        // 大小写判定
        obj.stat.correct.rst = this.case_determination ? (obj.stat.uipt == obj.text) : (obj.stat.uipt?.toLowerCase() == obj.text.toLowerCase())

        obj.stat.correct.rstelemInstantClass = obj.stat.uipt == '' ? 'user_empty' : obj.stat.correct.rst ? 'user_right' : 'user_wrong'

        obj.stat.correct.elemClass = this.sr_flag_instant ? obj.stat.correct.rstelemInstantClass : obj.stat.correct.elemClass
      }
    },

    correctAll() {
      this.sr_flag = true
      this.wordList.forEach(e => {
        if (e.stat) {
          this.correct(e)
          e.stat.correct.elemClass = e.stat.correct.elemInstantClass
        }
      })
    },

    open(url) {
      // const a = document.createElement('a')
      // a.href = url
      // a.target = '_blank'

      // document.body.appendChild(a);
      // a.click()
      // a.remove()

      const newWin = window.open(url, '', `width=${this.newWin_size.w},height=${this.newWin_size.h},left=${window.screen.width - this.newWin_size.w - 10},top=10`)
      newWin.focus()
    },

    del_word(index) {
      // delete this.wordSet[this.wordList[index].text]
      this.wordList.splice(index, 1)

      this.wordList.forEach(e => {
        if (e.index > index) e.index--
      })
    },

    fill_zero(num) {
      return num / 10 < 1 ? '0' + num : num
    },
    get_time() {
      const date = new Date()
      return `_${date.getFullYear()}${this.fill_zero(date.getMonth() + 1)}${this.fill_zero(date.getDate())}_${this.fill_zero(date.getHours())}${this.fill_zero(date.getMinutes())}`
    },
    export_json() {
      console.log(this.wordSet)

      const json = JSON.stringify(this.wordList, null, 2)
      const blob = new Blob([json], { type: "application/json" })
      const url = URL.createObjectURL(blob)
      const a = document.createElement("a")
      a.href = url
      a.download = this.export_info.filename + (this.export_info.addTime ? this.get_time() : '')
      a.click()
      URL.revokeObjectURL(url)
    },
    read_json(event) {
      const file = event.target.files[0]

      const reader = new FileReader()
      reader.onload = e => {
        this.wordList = JSON.parse(e.target.result)
        event.target.value = null
      }
      reader.readAsText(file)
    },
    read_dataList(jsonStr) {
      console.log(JSON.parse(jsonStr));
    },
    set_data(data, virtual) {
      this.baidu_process = 0
      this.baidu_process_err = 0

      if (virtual) {
        data.forEach(e => {
          e.virtual = true
        })
      }
      this.wordList = data
    },

    read_timestamp(timestamp) {
      const date = new Date(Math.floor(timestamp * 1000));

      const year = date.getFullYear();
      const month = ("0" + (date.getMonth() + 1)).slice(-2);
      const day = ("0" + date.getDate()).slice(-2);
      const hours = ("0" + date.getHours()).slice(-2);
      const minutes = ("0" + date.getMinutes()).slice(-2);
      const seconds = ("0" + date.getSeconds()).slice(-2);

      const formattedDate = year + "/" + month + "/" + day + " " + hours + ":" + minutes + ":" + seconds;

      return formattedDate
    },
    set_current(current) {
      for (let k in this.data_list) {
        this.data_list[k].s.current = false

        this.data_list[k].d.forEach(e => {
          if (k == current.group && e.filename == current.filename) {
            this.data_list[k].s.current = true

            e.current = true

            this.baidu_process = 0
            this.baidu_process_err = 0

            this.export_info.filename = (k ? k + '/' : '') + e.filename
            if (current.virtual) {
              e.data.forEach(e => {
                e.virtual = true
              })

              this.export_info.filename = (k ? k + '/_' : '_') + e.filename
            }
            this.wordList = e.data
          } else {
            e.current = false
          }
        })
      }

      // document.querySelectorAll('.data_item.current').forEach(elem => {
      //   elem.className = elem.className.replace('current', '')
      // })

      // e.target.closest('li').className += ' current'
    },
    set_ls_dataList(value) {
      this.export_info.export_path = value
      localStorage.setItem("wsExportPath", value)
    },
    get_ls_dataList() {
      const val = localStorage.getItem("wsExportPath")
      if (val) this.export_info.export_path = val
      return val
    },
    mixArr(arr) {
      const originArr = JSON.parse(JSON.stringify(arr))
      const narr = [];
      arr.forEach((e, i) => {
        narr[i] = originArr.splice(Math.floor(Math.random() * arr.length - i), 1)[0];
      })

      console.log(narr);
      return narr
    },
    reverseArr(arr) {
      this.reversed = true
      const originArr = JSON.parse(JSON.stringify(arr))
      const narr = []
      arr.forEach(() => narr.push(originArr.pop()))
      return narr
    },
    order_arr() {
      const temp = []
      this.wordList.forEach((e, i) => {
        temp[e.index] = e
      })

      return temp
    },
    ws_save() {
      this.$refs.wss_export.click()
    },
    win_preview(content, tit = 'preview') {
      const w = 800, h = 400

      // 创建新页面
      const newPage = window.open('', '', `width=${w},height=${h},left=${(window.screen.width - w) / 2},top=${(window.screen.height - h) / 4}`);

      // 注入HTML内容
      newPage.document.write(`<html><head><title>${tit}</title></head><body>${content}</body></html>`);

    }
  }
}

</script>


<style scoped>
* {
  margin: 0;
  padding: 0;
  cursor: default;
}

body {
  background: #ece8d9;
  min-width: 27rem;
}

button,
#ctrl_wrap,
#add_wrap,
.trans_wrap,
.word_wrap .ctrls {
  user-select: none !important;
  -webkit-user-select: none !important;
}


input[type=text] {
  text-indent: 1em;
}

input[type=checkbox],
input[type=radio] {
  cursor: pointer;
}

input:disabled {
  opacity: 0.6;
}
</style>
<style lang="less" scoped>
ul {
  li {
    list-style-type: none;
    padding: 0;
  }
}

.wrapper {
  transition: all .3s;
  min-width: 30rem !important;
}

.fixed_switch {
  position: absolute;
  left: 0.2rem;
  top: 0.2rem;


  /deep/ svg {
    width: 1rem;
    transition: all .3s;
    fill: none;
    stroke-width: 1rem;
    stroke: #000;
    transform: rotate(-45deg);
  }

  &:hover {

    /deep/ svg {
      fill: #0faef2;

      transform: rotate(0);
      stroke: transparent;
    }
  }
}

.fixed {
  position: sticky !important;
  top: 0 !important;
  z-index: 12 !important;
  width: 100% !important;
  border-radius: 0 0 0.2rem 0.2rem !important;
  margin-left: 0 !important;
  // margin-top: 0 !important;

  .fixed_switch {
    /deep/ svg {
      fill: #000;
      stroke: #000;
      transform: none;
    }
  }
}


.include_btn {
  margin-left: 0.3rem;
}

.checkbox {
  margin: 0 0.5em;
}

#shelter {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 100;
  background: #000000cc;
}

#wrap,
#ws_wrap,
#data_list,
#contnet_wrap {
  position: relative;
  margin: 0 auto;
  width: 90%;
  height: 96%;
  margin-top: 0.6rem;
  padding: 1rem 2rem;
  box-sizing: border-box;

  box-shadow: 0.06rem 0.06rem 0.5rem #00000066;
  border-radius: 0.25rem;

  &,
  * {
    transition: all 0.3s;
  }

  button {
    cursor: pointer;
  }
}

#wrap {
  background: #fff;
}

#data_list {
  background: #deeed3;

  * {
    font: 400 0.5rem auto;
  }

  ul {
    margin-bottom: 1em;
  }

  li {

    &.data_item,
    &.item_group {
      >div {
        display: flex;
        align-items: center;
        justify-content: space-between;

        .btns_wrap {
          user-select: none;

          >span {
            cursor: pointer;
            padding: 0.2rem;
            background: #11111122;
            margin-right: 0.3rem;

            &:hover {
              color: #eee;
              background: #00000066;
            }

            &:last-child {
              margin-right: 1rem;
            }
          }

          .del_file {
            position: relative;

            .ensure_wrap {
              position: absolute;
              right: 0;
              top: calc(100% + 0.1rem);
              background: #fff;
              box-shadow: 0.06rem 0.06rem 0.1rem #666;
              white-space: nowrap;
              z-index: 11;

              display: none;

              span {
                display: inline-block;
                padding: 0.3rem 0.6rem;
                margin: 0;
                color: #000 !important;

                &:hover {
                  background: #00000033;
                }

                &:hover.btn_dangerous {
                  background: #c53232;
                }
              }
            }

            &:hover {
              background: #9c151569;
            }
          }
        }
      }

    }

    &.sub_item {
      margin-left: 2em;
    }

    &.data_item {
      >div:first-child {
        padding: 0.2rem 0.4rem;

        >div {
          margin: 0.1rem 0;
        }

        span {
          font-weight: 100;
          margin-right: 2em;
        }

        .desc {
          color: #333;
          font-weight: 400;
        }

        span:last-child {
          margin-right: 0;
        }
      }

      &:hover {
        background: #00000033;
      }

      &.current {
        position: relative;
        background: #ffffff99;

        &::before {
          content: '';
          position: absolute;
          left: -0.3rem;
          width: 0.2rem;
          height: 100%;
          background: #84a7d4;
        }
      }
    }

    &.item_group {
      margin-top: 1em;
      padding: 0.5rem 0;

      &.group_current {
        transition: all 0.2s;
        position: relative;
        color: #e6a03d;

        // @c_size: 0.5rem;

        // &::before {
        //   content: '';
        //   position: absolute;
        //   left: -@c_size;
        //   top: calc(50% - @c_size / 2);
        //   width: @c_size;
        //   height: @c_size;
        //   border-radius: 50%;
        //   background: #eec68e99;
        // }
      }

      * {
        font: 800 0.6rem auto;
      }

      &:hover {
        background: #00000011;
      }


      .content {
        flex-grow: 1;
      }
    }

    li:first-child {
      margin-top: 0;
    }
  }
}

#ws_wrap {
  background: #eef7f1;
  z-index: 12;

  * {
    font: 400 0.7rem auto;
  }

  .option_content {
    display: flex;
    align-items: center;
    padding-bottom: 0.4rem;

    user-select: none;

    .checkbox {
      cursor: pointer;

      * {
        font: 400 0.7rem auto !important;
      }

      margin: 0 0.5rem;
    }

    .process_bar_wrap {
      display: flex;
      align-items: center;
      justify-content: space-around;

      * {
        font: 800 0.6rem auto;
      }

      width: 100%;

      .process_bar {
        // width: 90%;
        // margin-left: 5%;
        flex-basis: 90%;
        height: 1rem;
        background: #fff;
        border-radius: 0.5rem;

        .process_current {
          height: 100%;
          // width: 90%;
          border-radius: 0.5rem;
          background: #5bebd399;

          &.process_done {
            background: #74ee9aaa;
          }
        }
      }
    }
  }

  input {
    /* 填充空白 */
    flex-grow: 1;
    color: rgb(39, 199, 151);
    text-indent: 0.5em;
  }

  button {
    background: #aeeabc99;
    color: #d79577;
    box-shadow: 0.1rem 0.1rem 0.1rem #45b05e;
    text-shadow: 0.05rem 0.05rem 0.06rem #0faef2;
    font-size: 0.6rem;
    padding: 0.12rem 0.64rem;
    margin-left: 0.2rem;
    border: none;
    border-radius: 0.3rem;
    transition: all 0.2s;

    &:hover {
      background: #aeead499;
      box-shadow: 0.2rem 0.2rem 0.2rem #53d170bd;
    }

    &:active {
      background: #71efa1a4;
    }
  }
}

#ctrl_wrap {
  margin-bottom: 1em;
  // border-bottom: 0.06rem solid #69d8de;

  >div {
    margin-bottom: 1rem;
    display: flex;
    align-items: center;
    flex-wrap: wrap;

    .export_filename {
      flex-grow: 1;
    }

    input[type='checkbox'] {
      margin-right: 0.1rem;
    }
  }

  button {
    margin-right: 1em;
  }

  * {
    font: 400 0.7rem auto;
  }
}

#cbox_wrap {
  display: flex;
  align-items: center;

  >div {
    margin-right: 1rem;
  }
}

#add_wrap {
  display: flex;
  margin-bottom: 2em;

  input {
    flex-grow: 1;
  }

  * {
    font: 400 0.8rem auto;
  }
}

#contnet_wrap {
  margin-bottom: 6rem;

  .word_wrap {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    border: 1px solid #666;
    border-radius: 0.2rem;
    padding: 0.5rem;
    margin-bottom: 0.3rem;
    overflow: hidden;

    &.user_wrong {
      background: #df7a7a99;

      .word_del {
        color: #fff !important;
      }
    }

    .item_from {
      position: relative;
      text-align: right;
      flex-basis: 100%;
      opacity: 0.1;
      padding-right: 1em;
      // text-indent: 2em;

      &::before {
        content: '';
        position: absolute;
        // left: 1em;
        right: 0.5em;
        top: 0;
        background: #00000066;
        width: 0.2em;
        height: 100%;
      }

      &:hover {
        color: #56b6c2;
        opacity: 0.5;
      }
    }


    .star {
      margin-right: 1em;
    }

    .block,
    .note_wrap {

      /deep/ svg {
        cursor: pointer;
        width: 1.4rem;
        height: 1.4rem;
        vertical-align: sub;

        path {
          fill: transparent;
          stroke-width: 2rem;
          stroke: #666;
        }

        &:hover {
          path {
            fill: #F0D15599;
            stroke: #444;
          }
        }

      }
    }

    .starred {
      /deep/ path {
        fill: #F0D155 !important;
        stroke: #f6505e !important;
        transition: all .3s;
      }
    }


    .trans_baidu {
      display: flex;
      align-items: center;
      position: relative;
      margin-right: 0.5rem;
      padding: 0.2rem;
      height: 3rem;

      .icon_wrap {
        // background: #fff;

        /deep/ svg {
          width: 2rem;
        }
      }

      .mean_wrap {

        li {
          position: relative;
          list-style-type: decimal-leading-zero;
          margin-left: 3em;

          &::selection {
            background: #e5fdde;
          }

          &::after {
            content: '';
            position: absolute;
            bottom: 0;
            left: 25%;
            width: 0;
            height: 0.03rem;
            background: #417fea;
            transition: all .3s;
          }

          &:hover {
            background: #00000010;
            color: #6e4508;
            font-weight: bold;

            span {
              display: block;
              transform: scale(1.2);
              margin-left: 1rem;
            }

            &::after {
              left: 0;
              width: 100%;
            }
          }
        }

        >div {
          position: relative;
          display: flex;
          // align-items: center;
          font: 400 0.5rem auto;
          margin-bottom: 0.3rem;
          border: 0.05rem solid #ddd;
          padding: 0.2rem;

          ul {
            flex-basis: 80%;
            // width: 100%;
          }

          &:hover {
            background: #ffffff;
          }

          // &::after {
          //   content: '';
          //   position: absolute;
          //   bottom: -0.1rem;
          //   left: 1%;
          //   width: 80%;
          //   height: 0.05rem;
          //   background: #4778c7;
          // }

          &:last-child {
            margin-bottom: 0;
            // &::after {
            //   display: none;
            // }
          }
        }

        .w_pre {
          font: 800 0.8rem auto;
          margin-right: 0.5rem;

          &::selection {
            background: #f5dfa5;
          }
        }
      }

      .voice_wrap {
        /deep/ svg {
          width: 1em;
        }

        li {
          text-indent: 0.5em;

          &:hover {
            background: #fff;
          }

          span {
            padding: 0.1rem;
          }

          span:first-child {
            font: 800 0.6rem auto;
            user-select: none;
          }

          span:last-child {
            font: 400 0.8rem Calibri, Segoe;

            &:hover {
              background: #00000022;
            }

            &::selection {
              background: #f5e3e3;
              text-shadow: 0.02rem 0.02rem 0.02rem #989df2;
            }
          }
        }
      }

      .aud_wrap {
        h3 {
          font: 800 1rem auto;
          text-shadow:
            // 0.1rem 0 0.02rem #fff,
            0.06rem 0 0.02rem #90d4f1;

          &::selection {
            background: #74ecde;
          }
        }

        >div {
          margin-left: 1rem;
          display: flex;
          align-items: center;
        }

        .aud_item {
          display: flex;
          align-items: center;
          padding: 0 .3rem;

          &:hover {
            background: #00000033;
          }
        }

        .lang_type {
          font-size: 0.8rem;
          user-select: none;
        }

        /deep/ svg {
          width: 0.8rem;
          margin-right: .5rem;
        }
      }

      &::after {
        content: '';
        position: absolute;
        height: 90%;
        right: -0.3rem;
        top: 5%;
        width: 0.06rem;
        background: #e7e5e5;
      }

      @content_w: 16rem;

      .content {
        width: @content_w;
        margin-left: -@content_w;
        opacity: 0;
        // padding: 1.6rem 0;
        height: 2rem;
      }

      * {
        pointer-events: none;
      }

      &:hover {
        background: #00000011;
        // padding: 1.6rem 0;

        * {
          pointer-events: all;
        }

        .content {
          // animation-delay: 1s;
          // animation: show_bd normal 1s forwards;
          margin-left: 0;
          opacity: 1;
          transition: all .4s .2s;
          height: auto;
          // display: block;
        }

        /deep/ svg {
          fill: #1488f5;
        }

        .icon_wrap {
          transition: all .3s .6s;
          margin-left: -2rem;
          opacity: 0;
        }
      }

      @keyframes show_bd {
        0% {
          margin-left: -@content_w;
        }

        100% {
          margin-left: 0;
        }
      }

      svg {
        width: 2rem;
        fill: #000;
      }
    }

    .block {
      display: flex;
      align-items: center;
      // flex-grow: 1;

      >div:first-child {
        flex-grow: 1;
      }

      .word {
        display: flex;
        align-items: center;

        .word_text {
          font-size: 1.2rem;
        }
      }

    }

    &::before {
      content: '';
      transition: all .3s;
      position: absolute;
      left: -100%;
      top: 0;
      width: 100%;
      height: 100%;
      background: linear-gradient(45deg, #f8a63bda, 10%, #fff, transparent) !important;
      pointer-events: none;
      z-index: -1;
    }

    &.collected {
      // background: transparent !important;

      .word_text {
        letter-spacing: 0.1rem;
        color: #eb8014;
        text-shadow: 0.07rem 0.02rem 0.05rem #800606;
        transform: scale(1.2);
      }

      .mean {
        .mean_text {
          color: #7ddfd8;
          text-shadow: 0.05rem 0.02rem 0.05rem #060680;
        }
      }

      // * {
      //   z-index: 2;
      // }

      &::before {
        left: 0;
        background: linear-gradient(45deg, #f8a63bda, 10%, #fff, transparent) !important;
      }
    }

    &.user_right {
      background: #5cca9a99;
    }

    &.user_empty {
      background: #ffff7a99;
    }

    .word_text {
      &::selection {
        background: #e6cab3;
        color: #db7312;
        text-shadow: 0.06rem 0.06rem 0.06rem #3a4d3b
      }
    }

    .mean_text {

      &::selection {
        background: #b8e1c4;
        color: #2f7cf1;
        text-shadow: 0.06rem 0.06rem 0.06rem #ea5f1f;
      }

      /deep/ code {
        background: #eee;
        border-radius: 0.2rem;
        margin: 0 0.5em;
        font-family: md_font;
        padding: 0 0.2rem;
      }
    }

    .word_del {
      cursor: pointer;
      // width: 2em;
      right: 2em;
      position: absolute;
      color: #d64444;
      transition: all 0.2s;
      border-radius: 0.2rem;
      padding: 0.2rem;
      font-size: 0.7rem;

      &:hover {
        background: #d64444;
        color: #fff;
      }

    }

    .desc {
      color: #00000033;

      &::selection {
        background: #eee;
        color: #999;
      }
    }

    .word,
    .mean,
    .ctrls {
      display: flex;
      align-items: center;
    }

    .word {
      * {
        font-size: 1rem;
      }

      button {
        font-size: 0.7rem;
      }
    }

    .note_wrap {
      flex-basis: 100%;

      /* textarea {
        transition: none;
        width: 70%;
        min-width: 10rem;
      } */

      .ctrls {
        display: flex;
        align-items: center;
      }

      .mdEdit_wrap {
        margin-bottom: 0.5rem;

        button {
          margin: 0.2rem;
        }
      }
    }

    .audio_wrap {
      display: flex;

      /deep/ svg {
        width: 1em;
        vertical-align: middle;
      }

      .aud_item {
        display: flex;
        align-items: center;

        .lang_type {
          text-indent: 1em;
        }

        .svg {
          margin-right: 1em;
        }

        &:hover {
          background: #00000022;
        }
      }
    }

    .trans_wrap {
      font-size: 0.6rem;
      text-indent: 2em;
      margin-top: 0.3rem;

      .item {
        cursor: pointer;
        padding: 0.2rem;
        border-radius: 0.2rem;
        margin-right: 0.3rem;

        opacity: 0.3;

        &.t_baidu {
          background: #1488f5;
        }

        &.t_youdao {
          background: #fc011a;
        }

        &.t_bing {
          background: #106ebe;
        }


        &:hover {
          padding: 0.2rem 0.6rem;
          margin-left: 0.6rem;
          opacity: 0.6;
        }
      }

    }
  }
}

input {
  cursor: text;
  border: none;
  border-bottom: 0.06rem solid #666;
  outline: none;
  background: transparent;

  font: 400 0.8rem "Microsoft Yahei";
}

button {
  background: #eac0ae99;
  color: #62aaed;
  box-shadow: 0.06rem 0.06rem 0.12rem #d85a5a;
  text-shadow: 0.03rem 0.03rem 0.06rem #3b10be;
  padding: 0.12rem 0.24rem;
  border: none;
  border-radius: 0.3rem;
  transition: all 0.1s;

  &:hover {
    background: #eac0ae;
  }

  &:active {
    background: #e49b7b;
  }
}
</style>
<style lang="less" scoped>
@media screen and (max-width: 64rem) {
  input[type=text] {
    font-size: 0.6rem !important;
  }

  .fixed_switch {
    position: relative;
    display: flex;
    align-items: center;
    background: #00000011;
    padding: 0.2rem;
    box-sizing: border-box;
    border-radius: 0.2rem;
    margin-bottom: 0.6rem;

    &::after {
      content: '固定';
      font: 400 0.7rem md_font;
      text-indent: 1em;
    }


    &:hover {
      background: #00000022;
      letter-spacing: 0.2rem;

      /deep/ svg {
        transform: rotate(0);
      }
    }
  }

  .fixed {
    .fixed_switch {
      &::after {
        content: '已固定' !important;
        text-indent: 0;
      }
    }
  }

  #wrap,
  #ws_wrap,
  #data_list,
  #contnet_wrap {
    width: 100%;
    margin: 0;
    padding: 0.2rem 0.4rem;
    border-radius: 0;
  }

  #data_list {
    .current {
      background: #00000012 !important;
    }
  }

  #ws_wrap {
    padding-bottom: 2rem;
    padding-top: 1rem;
    flex-wrap: wrap;

    * {
      white-space: nowrap;
    }

    span {
      flex-shrink: 0;
    }

    input {
      // flex-basis: 100%;
    }

    button {
      flex-basis: 20%;
      margin-left: 0.5rem;
    }

    * {
      font-size: 1rem;
    }
  }

  #data_list {
    margin: 1rem;
    padding: 0.5rem;
    border-radius: 0.5rem;
    width: calc(100% - 2rem);
    box-sizing: border-box;
    background: #ffffff;

    .data_item {
      >div {
        display: block !important;

        .btns_wrap {
          margin: 0.4rem !important;

          >span {
            padding: 0.24rem 0.6rem !important;
          }
        }
      }
    }
  }

  #contnet_wrap {
    margin-top: 1rem;
    padding-top: 0.5rem;
    padding-bottom: 6rem;
  }

  body {
    background: #6fd1e531;
  }
}
</style>
<style lang="less">
@font-face {
  font-family: md_font;
  src: url('./assets/font/XiangZuoNiDeFanHuaSiJin-2.ttf');
}

.markdown-body {

  &,
  * {
    font-family: md_font !important;
  }
}
</style>
<style lang="less">
@h-font-size: 0.5rem;

.markdown_wrap {
  .vue-router-link {
    text-shadow: none;
    -webkit-text-stroke: 0.24rem transparent;
    // background: linear-gradient(to right, #df5ea0, #518ace);
    // background: linear-gradient(to right, #76df5e, #518ace);
    background: #01a14c;
    background-clip: text;
    -webkit-background-clip: text;
    color: #fff;
    letter-spacing: 0.2rem;
    // mix-blend-mode: difference

    &:hover {
      text-shadow: 1px 1px 0.1rem red;
      text-decoration: none;
    }
  }

  &,
  * {
    scroll-behavior: smooth;
  }

  padding: 0.2rem 1rem !important;
  background: #fff;
  overflow: auto !important;

  .katex_content,
  .MathJax_SVG_Display {
    padding: 0.3rem 0.2rem;
    margin: 0.2rem 0;
    transition: all 0.6s 0.3s;

    &:hover {
      background: #00000012;
    }
  }

  .katex_content {
    text-align: center;
  }

  .katex-html {
    display: none;
  }

}

#markdown_content {
  min-height: 100%;
  padding-bottom: 4rem;
}
</style>

<style lang="less">
.markdown_wrap {
  * {
    scroll-behavior: smooth;
  }

  #aside_menu {
    position: fixed;
    display: flex;
    /* flex-direction: row-reverse; */
    top: 10vh;
    left: 0;
    z-index: 1;
  }

  #menu_toggle span {
    cursor: pointer;
    display: block;
    text-align: center;
    width: 1em;
    height: 5em;
    line-height: 5em;
    background: #fefefecc;
    border-radius: 0 1rem 1rem 0;
    transition: all 0.2s;
  }

  #menu_toggle span:hover {
    background: #ddd;
  }

  .show #menu_toggle span:first-child {
    display: none;
  }

  .hide #menu_toggle>span:last-child {
    display: none;
  }

  #menu_content {
    cursor: default;
    background: #efefef;
    margin: 0;
    padding: 0;
    border-radius: 0 0 1rem 0;
    overflow: hidden;
  }

  #menu_content li * {
    margin: 0;
  }

  #menu_content li h3 {
    text-indent: 0.5em;
  }

  #menu_content li p {
    cursor: pointer;
    display: block;
    list-style-type: none;
    padding: 0.2em 0.3em;
    font: 400 0.7rem auto;
  }

  #menu_content p:hover {
    background: #ccc;
  }
}
</style>
<style lang="less">
.markdown-body {
  ::selection {
    background: #dce3ea;
  }

  img {
    vertical-align: middle;
  }

  & {
    padding: 1vh 1vw;
    background: #fff;
    overflow: auto;

    &:hover {
      box-shadow: 0.2rem 0.2rem 1rem #ddd;
    }
  }

  code {
    background: #eee;
    border-radius: 0.2rem;
    margin: 0 0.5em;
    padding: 0 0.2em;
  }

  table {
    margin: auto;
    table-layout: fixed
  }

  table td {
    padding: 0.2em 0.64em;
  }

  blockquote {
    position: relative;
  }

  pre {
    padding: 0 ! important;
    border-radius: 0.5rem ! important;
    overflow: none ! important;
    box-shadow: 1px 1px 1rem #ddd;
  }

  thead tr {
    background: #f6f8fa !important;
  }

  .code_wrap {
    position: relative;

    .code-block-header {
      position: absolute;
      width: 100%;
      z-index: 2;

      span {
        white-space: nowrap;
      }
    }

    pre {
      padding: 1rem !important;
      padding-top: 2rem !important;
    }
  }

  .code-block-header {
    border-radius: 0.5rem 0.5rem 0 0;
    text-align: right;
    background: #00000012;
    padding: 0.2em 1em;
    position: relative;
    box-shadow: 1px 1px 1rem #ffffff11;
  }

  .code-block-header * {
    font: 100 1rem auto;
    color: #b3b3b3;
  }

  .code-block-header div {
    position: relative;
    display: inline-block;
    cursor: pointer;
    margin-left: 1em;
  }

  .code-block-header div>span {
    display: block;
    position: relative;
  }

  .code-block-header div>span:first-child {
    position: absolute;
    cursor: default;
    top: -100%;
    opacity: 0;
    color: #65a665;
  }

  .code-block-header div>span:hover:last-child {
    color: #b3b;
  }

  #head_links {
    display: flex;
    justify-content: space-between;
  }

  .mark {
    font-size: 0.7em !important;
    vertical-align: top;
  }

  #content-block {
    max-width: 90vw;
    min-width: 24rem;
    margin: 0 auto;
  }
}

.md_topic_wrap {
  cursor: default;
  position: relative;
  border: dashed 1px transparent;
  margin-bottom: 2rem;

  li {
    list-style-type: none;

    a {
      color: #06ad7b;
    }
  }


  &:hover {
    border: 1px solid #ddd;
  }

}
</style>